package io.gitee.twoke.generator.engine.impl.generate.processor;

import io.gitee.twoke.generator.engine.impl.generate.output.OutputEntity;
import io.gitee.twoke.generator.engine.impl.template.TemplateFile;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;

import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

public abstract class AbstractTemplateGenerator implements TemplateGenerator {

    private final static String FILE_NAME_LOG_TAG = "FILE_NAME";
    private final static String FILE_CONTENT_LOG_TAG = "FILE_CONTENT";
    private VelocityEngine engine;

    public AbstractTemplateGenerator(VelocityEngine engine) {
        this.engine = engine;
    }

    @Override
    public void generate(GenerateContext context) {
        if (Objects.isNull(context.getTemplates())) {
            throw new IllegalArgumentException("templates is null");
        }
        generateFile(transformOutputEntity(context));
    }

    protected List<OutputEntity> transformOutputEntity(GenerateContext context) {
        return context.getTemplates().parallelStream().map(tpl -> {
            String content = getContent(context.getContext(), tpl);
            String filename = getFilename(context.getContext(), tpl);
            return OutputEntity.defaultBuilder()
                    .filename(filename)
                    .outputDir(context.getOutputDir())
                    .data(content.getBytes(StandardCharsets.UTF_8))
                    .params(createOutputEntityParams(filename, tpl))
                    .build();
        }).collect(Collectors.toList());
    }

    protected abstract void generateFile(List<OutputEntity> data);

    protected Map<String, Object> createOutputEntityParams(String filename, TemplateFile templateFile) {
        return new HashMap<String, Object>(){{
            put("filename", filename);
            put("templateFile", templateFile);
        }};
    }

    protected String getFilename(VelocityContext context, TemplateFile templateFile) {
        return evaluate(context, FILE_NAME_LOG_TAG, templateFile.getFilenameExpression());
    }

    protected String getContent(VelocityContext context, TemplateFile templateFile) {
        return evaluate(context, FILE_CONTENT_LOG_TAG, templateFile.getContent());
    }

    protected String evaluate(VelocityContext context, String logTag, String template) {
        StringWriter result = new StringWriter();
        engine.evaluate(context, result, logTag, template);
        return String.valueOf(result);
    }

}
